iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Software Development

30 天學習 Elasticsearch系列 第 22

Day 22 Elasticsearch - 搜尋簡介

  • 分享至 

  • xImage
  •  

該文章同步發佈於:我的部落格

也歡迎關注我的 Facebook 以及 Instagram 接收軟體相關的資訊!

在前面幾篇的文章中,我們已經把 Elasticsearch ( 以下簡稱 ES ) 的許多概念都大致上地帶過,這邊快速地複習一下現在我們學到了什麼:

  1. 如何針對 document 進行 CRUD?
  2. 如何設定 primary shard 以及 replica shard,以及 ES 是如何透過找到儲放資料的 shard?
  3. ES 是怎麼透過 seq_no 搭配 primary_term 來達成樂觀鎖?
  4. 介紹 Analyzer,也解釋為什麼需要 Analyzer
  5. 介紹 Inverted Indices 是如何儲存 text 的資料類型
  6. 資料類型帶來不同的儲存方式,但全文檢索是靠著 text 的資料類型所做到的
  7. 如何使用 ReIndex?以及透過 Alias 的方式來替換 Index

在大致上理解這些概念後,我們就可以進入到搜尋的環節,但在開始學習使用搜尋的 API 之前,我們需要建立一份有意義的 Index,這時候就可以利用我們學到的 bulk API 來導入這份 2000's 電影的資料。

這邊是下載的 Gist連結,請自行下載成檔案後,使用 bulk API 來導入這
份文件到 ES 之中。

簡單範例:

$ curl -H "Content-Type: application/x-ndjson" -XPOST "localhost:9202/_bulk" --data-binary "@bulk_movies.json"

你可能會遇到下面的錯誤訊息:

curl: (7) Failed to connect to localhost port 9202 after 4 ms: Couldn't connect to server

這很簡單,在開一個 node 然後 --publish 9202:9200 即可。

$ docker container run --name robert-es-node-3 --net elastic -it --publish 9202:9200 -m 1GB -e "xpack.security.enabled=false" -e "node.name=node-3" -e "discovery.seed_hosts=robert-es" -d docker.elastic.co/elasticsearch/elasticsearch:8.9.1

你也可以參考 Bulk Import 這篇文章 的方式,直接複製貼上然後導入,我已經整理好資料,讓它符合 NDJSON 的格式,所以應該不會有問題。

其他有關於 ES 的問題應該都可以往前面的文章找到答案,或是留言告訴我!

搜尋的兩種方式

ES 最主要有兩種方式可以搜尋,分別是 URI Searches 以及 Query DSL

簡單介紹一下這兩個差在哪裡:

URI Searches

可以直接透過 HTTP URI 的查詢參數執行搜尋,如下圖所示:

GET /movies/_search?q=title:days

從 URI 上可以很直覺地看到是針對 title 包含 days 的資料進行搜尋。

好處:

  1. 簡單易懂:直觀而且容易理解,不需要複雜的查詢語法。
  2. 快速測試:可以快速通過瀏覽器或 curl 命令進行測試和驗證。

壞處:

  1. 功能有限:只能進行簡單的查詢,不支持複雜查詢和資料的 aggregation。
  2. 不好閱讀:當查詢參數變多時,URL 可能變得冗長且難以理解。
  3. 長度限制:將查詢參數附加在 URL 上時,就需要考慮查詢參數的長度限制。

什麼時候可以使用?簡單的、不涉及複雜邏輯和 aggregation 的查詢。

順便一提,後面的查詢參數其實是 Lucene 的語法,所以可能還要熟悉一下 Lucene 會讓你使用起來更順手

Query DSL

這個是我自己比較推薦的方式,先用一個之前可能就見過的方式來查詢:

GET /movies/_search
{
  "query": {
    "match_all": {}
  }
}

接著 ES 會回應我們所有這個 Index 內的 documents ( 預設是顯示 10 筆 )

好處:

  1. 功能強大:可以進行複雜的查詢、過濾和 aggregation 的操作。
  2. 容易閱讀和撰寫:結構清晰,符合 JSON 格式,方便撰寫和閱讀。
  3. 高度靈活:可以精確地控制查詢的各個細節,包括排序、scoring 等等。

壞處:

  1. 學習成本:需要理解和學習 Query DSL 的語法和使用方法。
  2. 複雜性:相較於簡單的查詢,Query DSL 可能顯得過於繁瑣和複雜。

什麼時候可以使用?複雜的、需要精確控制的查詢和 aggregation 的操作。

DSL 是 Domain Specific Language 的縮寫,意指語法只使用在特定的場合,像是這個 Query DSL 就只用在 ES 的查詢之中

很顯然 Query DSL 的壞處就是麻煩,寫起來複雜,但這樣的痛苦在 Kibana 的 Dev tools 中得到緩解,因為 auto-completion 的關係,撰寫的時候不需要記一些特別的語法,可以縮短學習曲線。

理解 Response 的內容

如果圖片不容易閱讀的話,這是 response 大致上的樣貌:

{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2430,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "movies",
        "_id": "1",
        "_score": 1,
        "_ignored": [
          "extract.keyword"
        ],
        "_source": {
          "title": "102 Dalmatians",
          "year": 2000,
          "cast": [
            "Glenn Close",
            "Gérard Depardieu",
            "Alice Evans"
          ],
          "genres": [
            "Comedy",
            "Family",
            "Crime"
          ],
          "href": "102_Dalmatians",
          "extract": """102 Dalmatians is a 2000 American crime comedy film directed by Kevin Lima and produced by Edward S. Feldman and Walt Disney Pictures. The sequel to the 1996 film 101 Dalmatians, a live-action remake of the 1961 Disney animated film of the same name, it stars Glenn Close reprising her role as Cruella de Vil as she attempts to steal puppies for her "grandest" fur coat yet. Glenn Close and Tim McInnerny were the only two actors from the 1996 film to return for the sequel. The film received generally negative reviews from critics and was unable to achieve the box office success of its predecessor, although the film was nominated for the Academy Award for Best Costume Design.""",
          "thumbnail": "https://upload.wikimedia.org/wikipedia/en/f/fe/102_dalmatians_poster.jpg",
          "thumbnail_width": 220,
          "thumbnail_height": 327
        }
      },
    ...
    ]
  }
}

首先是最上面的 took,代表的是這次查詢耗費的時間,單位是 millisecond,所以這次查詢耗費了 0.005 秒。

第二個是 time_out 的 flag,很直覺地告訴我們這次的查詢有沒有超時。

第三個看到的是 _shards 這邊包含了 primary shard 以及 replica shard 兩種不同的 shards。

比較有趣的是 skipped 這個 key,它代表了 ES 判斷如果你要查詢的資料不在某一個 shard 之中,直接跳過某些 shard 來提高查詢的效率,常常適用於 range 的資料類型查詢。

需要注意的是這個 shard 可能包含了還沒有被分配到的 shard,如果這數字比你預期的還高,那大概是這個原因

接著進入到 hits 之中,從字面上就可以知道這代表的是符合查詢參數的結果:

我們先從 total 來說,value 代表了符合查詢的筆數,這個很好理解;但下面的 relation 代表的意思就是這次 value 結果是否精確,如果是 "eq" 代表說這次返回的數字是準確的,而另外一個可能返回的結果是 "gte" 代表 greater than or equal to,表示這個 value 是符合查詢結果的最低標。

至於為什麼會有這樣的情況,之後有機會會解釋,但大概可以查詢的關鍵字是 Deep Paging 或是 track_total_hits

再來是 max_score 代表的則是這些符合查詢的資料中,最符合的那份資料的得分,可以看到資料中也有會一個 _score 的欄位,有關於 scoring 的細節,之後會在仔細的解釋,這比較複雜,總之絕對不是 0 - 100 分的概念。

最後就是 hits 裡面的 hits,我知道這有點搞笑,但沒辦法,ES 要這樣取名就是這樣取,在這個陣列之中,就會包含符合查詢條件的資料,並且以 JSON 物件顯示。

看到 JSON 物件內,第一個 _index 是 index 的名字,你可能會問,我們不就是在一個 index 內搜尋了嗎?為什麼需要這個欄位呢?這是因為 ES 不止可以在一個 index 之中搜尋,所以這個欄位可以幫助我們辨別資料來自哪一個 index 之中。

_id_score 就跳過不談,要介紹的另外一個是 ignored 的陣列,裡面會列出在建立資料時被忽略的欄位,以我提供的例子來說:

extract.keyword 代表 extract 欄位的 keyword 資料類型超過字數限制,ES 預設是 256,所以超過的就沒有被建立到 inverted index 之中。

至於為什麼一個 extract 欄位有兩種資料類型呢?

這就是 Dynamic Mapping 做的事情了,有時候我們會需要針對同一個欄位做 text 以及 keyword 兩種資料類型,為的就是不同的目的,text 保證了全文的搜尋,而 keyword 則可以做到資料的 aggregation 以及排序。

最後則是 _source 欄位,也是之前介紹過的,我們當初建立資料時的內容,都會原封不動的在這個 key 裡面。

上述就是基本的 Search API 使用方式,以及在 response 之中欄位代表的意思,接著我們會來討論不同層級的搜尋方式,看看 ES 為什麼被稱作地表最強搜尋引擎。


上一篇
Day 21 Elasticsearch - ReIndex & Alias API
下一篇
Day 23 Elasticsearch - Term Level Query
系列文
30 天學習 Elasticsearch30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言